/*
 * author      : dormi330
 * date        : 2018/6/27
 * project     : mybatis
 * description : 购物车命令
 */

package com.deep.trade.domain.cart;

import com.deep.trade.common.TradeException;
import com.deep.trade.adaptor.required.DistributeLockService;
import com.deep.trade.adaptor.required.IdService;
import com.deep.trade.adaptor.required.sku.Sku;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class CommandOfCart {

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());
    private static final int EXPECT_CHANGED_COUNT_ONE = 1;

    private CartQueryRepository cartQueryRepository;
    private CartRepository cartRepository;
    private IdService idService;
    private DistributeLockService distributeLockService;

    @Autowired
    public CommandOfCart(
            CartQueryRepository cartQueryRepository
            , CartRepository cartRepository
            , IdService idService
            , DistributeLockService distributeLockService
    ) {
        this.cartQueryRepository = cartQueryRepository;
        this.cartRepository = cartRepository;
        this.idService = idService;
        this.distributeLockService = distributeLockService;
    }

    @Transactional
    public void addSkuToCart(String memberId, Sku sku, int lastQuantity) throws Exception {
        if (lastQuantity <= 0) throw new TradeException("cannot get distribute lock for add cartSku to sku");

        // 如果购物车已经有了, 则修改数量
        CartSku oldCartSku = cartQueryRepository.cartOfSpecificMemberAndSku(memberId, sku.getId());

        if (null != oldCartSku) {
            oldCartSku.setQuantity(lastQuantity);
            cartRepository.cartSkuQuantityChanged(oldCartSku);
            return;
        }

        CartSku cartSku = new CartSku();
        BeanUtils.copyProperties(sku, cartSku);
        cartSku.setId(idService.uuid());
        cartSku.setMemberId(memberId);
        cartSku.setQuantity(lastQuantity);
        cartSku.setSkuId(sku.getId());
        cartSku.setSkuVersion(sku.getVersion());

        // 防止添加多条记录
        if (!distributeLockService.getLock()) {
            throw new TradeException("cannot get distribute lock for add cartSku to sku");
        }

        try {
            if (cartRepository.skuAddToCart(cartSku) != EXPECT_CHANGED_COUNT_ONE)
                throw new TradeException("add to cart fail");
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        } finally {
            distributeLockService.releaseLock();
        }
    }

    // 从购物车中移除
    @Transactional
    public void removeSkuFromCart(String memberId, List<String> skuIdList) throws Exception {
        try {
            for (String skuId : skuIdList) {
                CartSku cartSku = cartQueryRepository.cartOfSpecificMemberAndSku(memberId, skuId);
                if (null == cartSku) throw new TradeException("in cart no such sku=" + skuId);
                if (cartRepository.removeCartSku(cartSku) != EXPECT_CHANGED_COUNT_ONE) {
                    throw new TradeException("remove cart item fail, change count != 1");
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
    }

    @Transactional
    public void alterQuantity(String memberId, String skuId, int lastQuantity) throws Exception {
        CartSku cartSku = cartQueryRepository.cartOfSpecificMemberAndSku(memberId, skuId);
        if (null == cartSku) throw new TradeException("no such sku in cart");

        cartSku.setQuantity(lastQuantity);

        try {
            if (cartRepository.cartSkuQuantityChanged(cartSku) != EXPECT_CHANGED_COUNT_ONE) {
                logger.error("alter cart quantity fail, change count != 1");
                throw new TradeException("alter cart quantity fail, change count != 1");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
    }

}